/*
 * Copyright kecp
 * Apr 24, 2010
 */

package LBS;

import Tool.Debugger;
import Tool.Toolkit;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Vector;
import org.json.me.JSONArray;
import org.json.me.JSONException;
import org.json.me.JSONObject;

/**
 * 地址解析服务
 * 提供地点名到地理坐标的双向转换
 * @author kecp
 */
public class AddressSrv {
    static final String apiKey = GoogleMap.apiKey;

    
    /** 地点容器，用来存放查找到的多个坐标到地点名的转换结果 */
    Vector as_loctVec = null;

    /*
     * Google
     * 通过 HTTP 进行地址解析
        还可以使用服务器端脚本来直接访问地图 API 地址解析器。使用客户端地址解析器时不建议使用这种方法，但该方法在进行调试时或 JavaScript GClientGeocoder 对象不可用时却很有用。
        要访问地图 API 地址解析器，请访问 http://ditu.google.cn/maps/geo? 并在网址中添加以下参数：
        q（必填）- 您要进行地址解析的地址。
        key（必填）- 您的 API 密钥。
        sensor（必填）- 指示地址解析请求是否来自装有位置传感器的设备。该值必须为 true 或 false。
        output（必填）- 生成时输出应采用的格式。选项有 xml、kml、csv 或默认选项 json。
        ll（可选）- 视口中心的 {经度,纬度}，表示为以逗号分隔的字符串（例如“ll=-117.773438,40.479581”）。仅当将 spn 参数也传递给地址解析器时此参数才有意义。
        spn（可选）- 视口的“范围”，表示为以逗号分隔的 {经度,纬度} 字符串（例如“spn=22.5,11.1873”）。仅当将 ll 参数也传递给地址解析器时此参数才有意义。
        gl（可选）- 国家/地区代码，指定为 ccTLD（“顶级域”）双字符值。
     */
    final static String requestUrl = "http://ditu.google.cn/maps/geo?";

    private String makeRequest( String addr ) {
        StringBuffer sb = new StringBuffer("");
        String addrEnc = Toolkit.utf8StrEncToHexStr(addr, "%");
        sb.append(requestUrl);
        sb.append("&output=json&sensor=false&key=").append(apiKey);
        sb.append("&q=").append(addrEnc);
        return sb.toString();
    }


    /**
     * 解析地址并保存到容器中
     * @param jsonString 解析json格式的响应
     * @return  返回成功解析的地址数量
     *
     */
    private  int parseJSON(String jsonString) {
         Location loc ;
         if( as_loctVec == null )
             as_loctVec = new Vector();
         else
             as_loctVec.removeAllElements();
         
         try {
            JSONObject o = new JSONObject(jsonString);
            JSONArray pmArray = o.getJSONArray("Placemark");
            for( short i=0; i<pmArray.length(); i ++ ) {
                try{
                loc = new Location();
                JSONObject pm = pmArray.getJSONObject(i);
                loc.setName(pm.getString("address"));
                loc.setAccuracy( pm.getJSONObject("AddressDetails").getString("Accuracy"));

                JSONObject pos = pm.getJSONObject("Point");
                JSONArray cd = pos.getJSONArray("coordinates");
                loc.setLon( cd.getString(0));
                loc.setLat(  cd.getString(1) );
                Debugger.addDebugInfo("Address: " + loc.toString());
                as_loctVec.addElement(loc);
                }catch(JSONException e) {
                    e.printStackTrace();
                   continue;
                }
            }
        } catch(JSONException e) {
            e.printStackTrace();
            return 0;
        }
      return as_loctVec.size();
    }

    /**
     *
     * @return 上一次地址解析的结果
     */
    public Vector getCurLocts() {
        return as_loctVec;
    }

    /**
     * 搜索得到给定地点名对应的坐标地址
     * @param addr   地址字符串，地点名
     * @return  搜索到的地点数量.实际结果使用getCurLocts获得
     * @see getCurLocts
     */
    public int  searchLocation( String addr ) {
        String str =  makeRequest(addr) ;
        String response = null;
        int n = 0;
        try
        {
            Debugger.addDebugInfo("request to google gegoding");
            Debugger.printDebugInfo(str);
            response = Toolkit.utfBytesToString(LocApiComLBS.getHttp(str));
        } catch (IOException ex) {
            ex.printStackTrace();
            return 0;
        }
        if( response != null ) {
            Debugger.addDebugInfo("response from google gegoding");
            Debugger.printDebugInfo(response);
            n = parseJSON( response );
        }
        return n;
    }

    public static  void testAddressSrv() {
        AddressSrv addrSrv = new AddressSrv();
        if(  addrSrv.searchLocation("广州北京路") > 0) {
            Location loct ;
            Vector locts = addrSrv.getCurLocts();
            Enumeration enums = locts.elements();
            while( enums.hasMoreElements() ){
                loct = (Location) enums.nextElement();
                Debugger.addDebugInfo(loct.toString() );
            }
        }
    }

    String parseAddressLookup( String json ) {

        String str = null;
        try {

            JSONObject o = new JSONObject(json);
            JSONArray pmArray = o.getJSONArray("results");
            o = pmArray.getJSONObject(0);
            str = o.getString("formatted_address");

        } catch (JSONException ex) {
            ex.printStackTrace();
        }
        return str;
    }

    public String addressLookup( Location loct ) {

        String str = "http://maps.google.com/maps/api/geocode/json?sensor=false";
        StringBuffer sb = new StringBuffer( str );

        sb.append("&latlng=");
        sb.append(loct.getLat());
        sb.append(",");
        sb.append(loct.getLon());

        String response = null;
        int n = 0;
        try
        {
            String request = sb.toString();
            response = Toolkit.utfBytesToString(LocApiComLBS.getHttp(request));
             Debugger.printDebugInfo(request);
             Debugger.addDebugInfo("address lookup request");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        if( response != null ) {
            String address = parseAddressLookup(response);
            Debugger.printDebugInfo(response);
            Debugger.addDebugInfo("Address: " + address);
            return address;
        }
        else
            return null;
    }

    
}
